from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.uix.spinner import Spinner
from kivy.uix.checkbox import CheckBox
from kivy.uix.filechooser import FileChooserListView
from kivy.clock import Clock, mainthread
from kivy.core.window import Window
from kivy.properties import StringProperty, ListProperty
import os
import threading
import sqlite3
from datetime import datetime


# 初始化窗口尺寸（模拟移动设备）
Window.size = (480, 800)


class DatabaseManager:
    """数据库管理类，处理备注数据的存储与查询"""
    def __init__(self, db_name="file_notes.db"):
        self.conn = sqlite3.connect(db_name)
        self.cursor = self.conn.cursor()
        self._init_table()

    def _init_table(self):
        """创建备注表"""
        self.cursor.execute('''
            CREATE TABLE IF NOT EXISTS file_notes (
                file_path TEXT PRIMARY KEY,
                note TEXT,
                update_time TIMESTAMP
            )
        ''')
        self.conn.commit()

    def get_note(self, file_path):
        """获取文件备注"""
        self.cursor.execute("SELECT note FROM file_notes WHERE file_path=?", (file_path,))
        result = self.cursor.fetchone()
        return result[0] if result else ""

    def save_note(self, file_path, note):
        """保存/更新文件备注"""
        self.cursor.execute('''
            INSERT OR REPLACE INTO file_notes 
            (file_path, note, update_time) 
            VALUES (?, ?, ?)
        ''', (file_path, note, datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
        self.conn.commit()

    def close(self):
        """关闭数据库连接"""
        self.conn.close()


class ScanThread(threading.Thread):
    """文件扫描线程，后台执行避免UI阻塞"""
    def __init__(self, target_dir, file_types, callback):
        super().__init__()
        self.target_dir = target_dir
        self.file_types = file_types
        self.callback = callback
        self.stop_flag = False

    def run(self):
        """执行扫描逻辑"""
        try:
            files = []
            for root, _, file_names in os.walk(self.target_dir):
                # 响应停止信号
                if self.stop_flag:
                    break
                for file_name in file_names:
                    # 过滤文件类型
                    if self.file_types and not any(
                        file_name.lower().endswith(ext.lower()) 
                        for ext in self.file_types
                    ):
                        continue
                    file_path = os.path.join(root, file_name)
                    try:
                        file_size = os.path.getsize(file_path) / (1024 * 1024)  # MB
                        files.append({
                            "name": file_name,
                            "path": file_path,
                            "size": f"{file_size:.2f} MB",
                            "parent": root
                        })
                    except Exception as e:
                        print(f"无法访问文件 {file_path}: {e}")
            # 扫描完成后回调UI线程更新
            Clock.schedule_once(lambda dt: self.callback(files))
        except Exception as e:
            Clock.schedule_once(lambda dt: self.callback([], str(e)))

    def stop(self):
        """停止扫描线程"""
        self.stop_flag = True


class FileItem(BoxLayout):
    """文件列表项组件，展示单个文件信息及操作"""
    file_info = ListProperty([])  # [文件名, 路径, 大小]
    note_preview = StringProperty("")  # 备注预览

    def __init__(self, file_data, on_action, **kwargs):
        super().__init__(** kwargs)
        self.orientation = "horizontal"
        self.size_hint_y = None
        self.height = 80
        self.padding = [10, 5]
        self.spacing = 10

        self.file_data = file_data
        self.on_action = on_action  # 回调函数：处理文件操作

        # 加载备注预览
        self.note_preview = self._get_note_preview()

        # 左侧信息区
        info_layout = BoxLayout(orientation="vertical", size_hint_x=0.7)
        info_layout.add_widget(Label(
            text=file_data["name"], 
            size_hint_y=0.4, 
            halign="left", 
            valign="center",
            text_size=(self.width * 0.7 - 20, None)
        ))
        info_layout.add_widget(Label(
            text=f"大小: {file_data['size']}", 
            size_hint_y=0.3, 
            color=(0.5, 0.5, 0.5, 1), 
            font_size=12,
            halign="left"
        ))
        info_layout.add_widget(Label(
            text=f"备注: {self.note_preview}", 
            size_hint_y=0.3, 
            color=(0.2, 0.6, 0.8, 1), 
            font_size=10,
            halign="left"
        ))

        # 右侧操作按钮
        action_btn = Button(
            text="...", 
            size_hint_x=0.15, 
            background_color=(0.9, 0.9, 0.9, 1)
        )
        action_btn.bind(on_press=self.show_action_popup)

        self.add_widget(info_layout)
        self.add_widget(action_btn)

    def _get_note_preview(self):
        """获取备注预览（前20个字符）"""
        note = App.get_running_app().db_manager.get_note(self.file_data["path"])
        return note[:20] + "..." if len(note) > 20 else note

    def show_action_popup(self, instance):
        """显示文件操作弹窗"""
        popup_layout = BoxLayout(orientation="vertical", padding=10, spacing=5)
        actions = [
            ("打开文件", "open"),
            ("重命名", "rename"),
            ("删除文件", "delete"),
            ("复制路径", "copy_path"),
            ("编辑备注", "edit_note")
        ]

        for text, action in actions:
            btn = Button(text=text, size_hint_y=None, height=40)
            btn.bind(on_press=lambda x, a=action: self.handle_action(a))
            popup_layout.add_widget(btn)

        popup = Popup(
            title=self.file_data["name"],
            content=popup_layout,
            size_hint=(0.8, None),
            height=300,
            auto_dismiss=True
        )
        popup_layout.add_widget(Button(
            text="关闭", 
            size_hint_y=None, 
            height=40,
            on_press=popup.dismiss
        ))
        popup.open()
        self.current_popup = popup

    def handle_action(self, action):
        """处理文件操作"""
        self.current_popup.dismiss()
        self.on_action(action, self.file_data)


class FileTypeSelector(Popup):
    """文件类型选择器弹窗"""
    def __init__(self, selected_types, on_confirm, **kwargs):
        super().__init__(** kwargs)
        self.title = "选择文件类型"
        self.size_hint = (0.9, 0.7)
        self.selected_types = selected_types.copy()
        self.on_confirm = on_confirm  # 确认回调

        # 常见文件类型分类
        self.file_types = {
            "图片": [".jpg", ".jpeg", ".png", ".gif", ".bmp"],
            "文档": [".txt", ".pdf", ".doc", ".docx", ".xls", ".xlsx"],
            "视频": [".mp4", ".avi", ".mov", ".mkv"],
            "音频": [".mp3", ".wav", ".flac"],
            "代码": [".py", ".java", ".cpp", ".html", ".js"]
        }

        layout = BoxLayout(orientation="vertical")
        scroll = ScrollView()
        grid = GridLayout(cols=1, spacing=10, size_hint_y=None)
        grid.bind(minimum_height=grid.setter("height"))

        # 添加类型复选框
        for category, exts in self.file_types.items():
            grid.add_widget(Label(text=category, size_hint_y=None, height=30))
            for ext in exts:
                row = BoxLayout(orientation="horizontal", size_hint_y=None, height=30)
                cb = CheckBox(
                    size_hint_x=0.2,
                    active=ext in self.selected_types
                )
                cb.bind(active=lambda x, e=ext: self.update_selection(e, x.active))
                row.add_widget(cb)
                row.add_widget(Label(text=ext, size_hint_x=0.8))
                grid.add_widget(row)

        scroll.add_widget(grid)
        layout.add_widget(scroll)

        # 确认按钮
        confirm_btn = Button(text="确认", size_hint_y=None, height=50)
        confirm_btn.bind(on_press=self.confirm)
        layout.add_widget(confirm_btn)

        self.content = layout

    def update_selection(self, ext, is_active):
        """更新选中的文件类型"""
        if is_active and ext not in self.selected_types:
            self.selected_types.append(ext)
        elif not is_active and ext in self.selected_types:
            self.selected_types.remove(ext)

    def confirm(self, instance):
        """确认选择并关闭弹窗"""
        self.dismiss()
        self.on_confirm(self.selected_types)


class MobileScannerApp(App):
    """主应用类"""
    status_text = StringProperty("就绪")
    count_value = StringProperty("0")

    def __init__(self, **kwargs):
        super().__init__(** kwargs)
        self.db_manager = DatabaseManager()  # 初始化数据库
        self.files = []  # 所有文件列表
        self.filtered_files = []  # 过滤后的文件列表
        self.current_dir = os.path.expanduser("~")  # 默认扫描目录（用户主目录）
        self.selected_file_types = []  # 选中的文件类型
        self.scan_thread = None  # 扫描线程实例

    def build(self):
        """构建UI界面"""
        self.main_layout = BoxLayout(orientation="vertical")

        # 1. 顶部控制区
        top_layout = BoxLayout(
            orientation="horizontal",
            size_hint_y=None,
            height=50,
            padding=5,
            spacing=5
        )

        # 目录选择按钮
        self.dir_label = Label(
            text=os.path.basename(self.current_dir),
            size_hint_x=0.4,
            halign="center",
            valign="center"
        )
        dir_btn = Button(text="选择目录", size_hint_x=0.3)
        dir_btn.bind(on_press=self.choose_directory)

        # 文件类型选择按钮
        type_btn = Button(text="文件类型", size_hint_x=0.3)
        type_btn.bind(on_press=self.choose_file_types)

        top_layout.add_widget(self.dir_label)
        top_layout.add_widget(dir_btn)
        top_layout.add_widget(type_btn)
        self.main_layout.add_widget(top_layout)

        # 2. 搜索区
        search_layout = BoxLayout(
            orientation='horizontal',
            spacing=5,
            size_hint_y=None,
            height=40,
            padding=[5, 0]
        )
        self.search_input = TextInput(
            text='',
            hint_text='搜索',
            multiline=False,
            size_hint_x=0.7
        )
        self.search_mode = Spinner(
            text='任意字符',
            values=['任意字符', '备注搜索'],
            size_hint_x=0.3
        )
        self.search_input.bind(text=self.on_search_text_change)
        search_layout.add_widget(self.search_input)
        search_layout.add_widget(self.search_mode)
        self.main_layout.add_widget(search_layout)

        # 3. 扫描按钮和状态区
        scan_layout = BoxLayout(
            orientation="horizontal",
            size_hint_y=None,
            height=40,
            padding=5,
            spacing=10
        )
        self.scan_btn = Button(text="开始扫描", size_hint_x=0.4)
        self.scan_btn.bind(on_press=self.toggle_scan)
        self.status_label = Label(
            text=self.status_text,
            size_hint_x=0.3,
            color=(0.2, 0.6, 0.8, 1)
        )
        count_layout = BoxLayout(orientation="horizontal", size_hint_x=0.3)
        count_layout.add_widget(Label(text="文件数:"))
        count_layout.add_widget(Label(text=self.count_value, id="count"))
        scan_layout.add_widget(self.scan_btn)
        scan_layout.add_widget(self.status_label)
        scan_layout.add_widget(count_layout)
        self.main_layout.add_widget(scan_layout)

        # 4. 文件列表区
        self.file_list_layout = GridLayout(
            cols=1,
            spacing=5,
            size_hint_y=None
        )
        self.file_list_layout.bind(minimum_height=self.file_list_layout.setter("height"))
        
        scroll_view = ScrollView()
        scroll_view.add_widget(self.file_list_layout)
        self.main_layout.add_widget(scroll_view)

        return self.main_layout

    def choose_directory(self, instance):
        """选择扫描目录"""
        def on_select(paths):
            if paths:
                self.current_dir = paths[0]
                self.dir_label.text = os.path.basename(self.current_dir)
        
        popup = Popup(
            title="选择扫描目录",
            content=FileChooserListView(
                path=self.current_dir,
                on_submit=lambda x, y: on_select(x) or popup.dismiss()
            ),
            size_hint=(0.9, 0.8)
        )
        popup.open()

    def choose_file_types(self, instance):
        """选择文件类型"""
        FileTypeSelector(
            selected_types=self.selected_file_types,
            on_confirm=self.update_file_types
        ).open()

    def update_file_types(self, types):
        """更新选中的文件类型"""
        self.selected_file_types = types
        self.status_text = f"已选择 {len(types)} 种文件类型"
        self.status_label.text = self.status_text

    def toggle_scan(self, instance):
        """开始/停止扫描"""
        if self.scan_thread and self.scan_thread.is_alive():
            # 停止扫描
            self.scan_thread.stop()
            self.scan_btn.text = "开始扫描"
            self.status_text = "扫描已停止"
        else:
            # 开始扫描
            self.status_text = "扫描中..."
            self.scan_btn.text = "停止扫描"
            self.scan_thread = ScanThread(
                target_dir=self.current_dir,
                file_types=self.selected_file_types,
                callback=self.on_scan_complete
            )
            self.scan_thread.start()

    @mainthread
    def on_scan_complete(self, files, error=None):
        """扫描完成回调（UI线程）"""
        self.scan_btn.text = "开始扫描"
        if error:
            self.status_text = f"扫描错误: {error}"
            return

        self.files = files
        self.status_text = f"扫描完成（{len(files)}个文件）"
        self.filter_files(self.search_input.text)  # 触发过滤刷新

    def on_search_text_change(self, instance, value):
        """搜索文本变化时触发过滤"""
        self.filter_files(value)

    def filter_files(self, search_text):
        """过滤文件列表，支持文件名和备注搜索"""
        if not search_text.strip():
            self.filtered_files = self.files.copy()
        else:
            search_lower = search_text.lower()
            search_mode = self.search_mode.text
            self.filtered_files = []

            for file in self.files:
                # 获取文件备注
                note = self.db_manager.get_note(file["path"])
                
                # 根据搜索模式过滤
                if search_mode == "任意字符":
                    # 同时匹配文件名或备注
                    if search_lower in file["name"].lower() or search_lower in note.lower():
                        self.filtered_files.append(file)
                elif search_mode == "备注搜索":
                    # 仅匹配备注
                    if search_lower in note.lower():
                        self.filtered_files.append(file)

        # 更新UI显示
        self.update_file_list()
        self.count_value = str(len(self.filtered_files))

    def update_file_list(self):
        """更新文件列表UI"""
        # 清空现有列表
        self.file_list_layout.clear_widgets()
        
        # 添加过滤后的文件
        for file in self.filtered_files:
            self.file_list_layout.add_widget(
                FileItem(
                    file_data=file,
                    on_action=self.handle_file_action
                )
            )

    def handle_file_action(self, action, file_data):
        """处理文件操作回调"""
        if action == "edit_note":
            self.show_note_editor(file_data)
        elif action == "copy_path":
            self.copy_to_clipboard(file_data["path"])
        # 其他操作（打开/重命名/删除）可根据需求实现
        else:
            self.status_text = f"操作 {action} 已触发（待实现）"

    def show_note_editor(self, file_data):
        """显示备注编辑弹窗"""
        current_note = self.db_manager.get_note(file_data["path"])
        note_input = TextInput(
            text=current_note,
            multiline=True,
            size_hint_y=0.8
        )

        layout = BoxLayout(orientation="vertical", padding=10, spacing=10)
        layout.add_widget(Label(text=f"编辑 {file_data['name']} 的备注"))
        layout.add_widget(note_input)

        def save_note(instance):
            self.db_manager.save_note(file_data["path"], note_input.text)
            popup.dismiss()
            self.filter_files(self.search_input.text)  # 刷新列表（更新备注预览）
            self.status_text = "备注已保存"

        save_btn = Button(text="保存", size_hint_y=None, height=40)
        save_btn.bind(on_press=save_note)
        layout.add_widget(save_btn)

        popup = Popup(
            title="编辑备注",
            content=layout,
            size_hint=(0.9, 0.6)
        )
        popup.open()

    def copy_to_clipboard(self, text):
        """复制文本到剪贴板（简化实现）"""
        # 实际移动设备需使用平台API，此处模拟
        self.status_text = "路径已复制到剪贴板"

    def on_stop(self):
        """应用关闭时清理资源"""
        self.db_manager.close()
        if self.scan_thread and self.scan_thread.is_alive():
            self.scan_thread.stop()
        super().on_stop()


if __name__ == "__main__":
    MobileScannerApp().run()